package cc.liyinghao.webSocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Slf4j
@Configuration
public class NettyWebSocketServer {

    private static final int PORT = 8889;
    private final String URL = "/ws";

    //处理连接
    private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    //处理请求
    private final EventLoopGroup workerGroup = new NioEventLoopGroup(NettyRuntime.availableProcessors());

    /**
     * 启动 ws server
     */
    @PostConstruct //容器初始化完成后 管道初始化
    public void start() throws InterruptedException {
        run();
    }

    /**
     * 销毁
     */
    @PreDestroy
    public void destroy() {
        Future<?> future = bossGroup.shutdownGracefully();
        Future<?> future1 = workerGroup.shutdownGracefully();
        future.syncUninterruptibly();
        future1.syncUninterruptibly();
        log.info("销毁成功");
    }


    /**
     * netty启动
     */
    public void run() throws InterruptedException {
        // 服务器启动引导对象
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 128) //设置等待连接队列的最大长度
                .option(ChannelOption.SO_KEEPALIVE, true) //开启 TCP 长连接，防止连接闲置过久被关闭
                .handler(new LoggingHandler(LogLevel.INFO)) // 为 bossGroup 添加 日志处理器
                .childHandler(new ChannelInitializer<SocketChannel>() { //设置 子通道（客户端连接通道） 的初始化逻辑。
                    @Override //在 每一个新的客户端连接 建立时调用。
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        // Netty 提供的心跳检测处理器，用于检测 读、写、读写 是否超时 30表示30秒 0表示不处理
                        pipeline.addLast(new IdleStateHandler(0, 0, 0));
                        // HTTP 编解码器 让 Netty 服务器能够解析 HTTP 请求，并生成 HTTP 响应。
                        pipeline.addLast(new HttpServerCodec());
                        // 用于支持 大数据流传输（例如 文件下载、WebSocket 大文件传输）避免发送大数据时 内存占用过高
                        pipeline.addLast(new ChunkedWriteHandler());
                        // HTTP 消息聚合器，将 HTTP 片段合并成完整的 HTTP 请求/响应，Netty 默认的 HTTP 处理是分段的
                        pipeline.addLast(new HttpObjectAggregator(8192));
                        // 解析 自定义 HTTP 头信息
                        pipeline.addLast(new HttpHeadersHandler());
                        // WebSocket 协议处理器，用于处理 WebSocket 握手、控制帧、文本帧、二进制帧等
                        pipeline.addLast(new WebSocketServerProtocolHandler(URL));
                        // 自定义 WebSocket 处理器，处理 WebSocket 文本帧
                        pipeline.addLast(new NettyWebSocketServerHandler());
                    }
                });
        serverBootstrap.bind(PORT).sync();
    }
}
